home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-02-07 | 35.2 KB | 979 lines | [TEXT/MPS ] |
- {-------------------------------------------------------------------------------
- #
- # Apple Macintosh Developer Technical Support
- #
- # Code for Process Manager utilities
- #
- # Program: ProcDoggie
- # File: UProcessUtils.inc1.p - Pascal Implementation
- #
- # by: Forrest Tanaka
- #
- # Copyright © 1988-1991 Apple Computer, Inc.
- # All rights reserved.
- #
- -------------------------------------------------------------------------------}
- {[j=20/57/1$] Pasmat Options}
- {$R-}
-
-
- CONST
- kCaseSens = TRUE; {Pass to EqualString for case-sensitive check}
- kDiacSens = TRUE; {Pass to EqualString for diacritical-sensitive check}
-
-
- {$S ProcessUtils}
- (*******************************************************************************
- * Private: EqualFSSpec - Check equality of FSSpec records
- *
- * EqualFSSpec returns TRUE if the file specified by spec1 refers to the same
- * file as the one specified by spec2. Otherwise, EqualFSSpec returns FALSE.
- *
- * To compare names, I’m using EqualString with no case sensitivity, but with
- * sensitivity to diacriticals. This isn’t usually the recommended way of
- * comparing strings, because the Script Manager has routines for comparing
- * strings in a more sophisticated, localizable way. But the File Manager uses
- * _CmpString, which is the assembly language equivalent of EqualString, so
- * that’s the way I must do things here.
- *******************************************************************************)
-
- FUNCTION EqualFSSpec (spec1: FSSpec;
- spec2: FSSpec): Boolean;
-
- BEGIN
- EqualFSSpec := (spec1.vRefNum = spec2.vRefNum) AND
- (spec1.parID = spec2.parID) AND
- (EqualString (spec1.name, spec2.name, NOT kCaseSens,
- kDiacSens))
- END;
-
-
- {$S ProcessUtils}
- (*******************************************************************************
- * Public: CreateDocList
- *
- * A document list record is allocated and initialized. Pretty simple.
- *******************************************************************************)
-
- FUNCTION CreateDocList (openOrPrint: LaunchModeCode): DocListHnd;
-
- VAR
- newList: DocListHnd; {Handle to the new DocListRec}
-
- BEGIN
- IF (openOrPrint = kOpenLaunch) OR (openOrPrint = kPrintLaunch) THEN
- BEGIN
- newList := DocListHnd(NewHandle (SIZEOF (DocListRec)));
- IF newList <> NIL THEN
- BEGIN
- newList^^.docList := NIL;
- newList^^.openPrint := openOrPrint
- END;
- CreateDocList := newList
- END
- END;
-
-
- {$S ProcessUtils}
- (*******************************************************************************
- * Public: IsEmptyDocList
- *
- * If the document list record is NIL, or if the docList field is NIL, then the
- * given document list is empty.
- *******************************************************************************)
-
- FUNCTION IsEmptyDocList (theList: DocListHnd): Boolean;
-
- BEGIN
- IsEmptyDocList := (theList = NIL) | (theList^^.docList = NIL)
- END;
-
-
- {$S ProcessUtils}
- (*******************************************************************************
- * Public: AddToDocList
- *
- * A new document list entry is allocated and then "newFile" is copied into its
- * docFile field. It is then added to end of "theList".
- *******************************************************************************)
-
- FUNCTION AddToDocList (newFile: FSSpec;
- theList: DocListHnd): OSErr;
-
- VAR
- newEntry: DocListEntryHnd; {Handle to the new DocListEntryRec}
- currEntry: DocListEntryHnd; {Handle to DocListEntryRec being checked}
-
- BEGIN
- (* Create a new document list entry *)
- newEntry := DocListEntryHnd (NewHandle (SIZEOF (DocListEntryRec)));
- IF newEntry <> NIL THEN
- BEGIN
- (* Initialize the new document list entry *)
- newEntry^^.next := NIL;
- newEntry^^.docFile := newFile;
-
- IF IsEmptyDocList (theList) THEN
- theList^^.docList := newEntry
- ELSE
- BEGIN
- (* Start from the head of the list *)
- currEntry := theList^^.docList;
-
- (* Find the end of the list *)
- WHILE currEntry^^.next <> NIL DO
- currEntry := currEntry^^.next;
-
- (* Attach the new entry to the end of the list *)
- currEntry^^.next := newEntry
- END;
- AddToDocList := noErr
- END
- ELSE
- AddToDocList := MemError
- END;
-
-
- {$S ProcessUtils}
- (*******************************************************************************
- * Private: DisposeAllDocEntries - Dispose of all document list entries
- *
- * Ahhh. . . good old, basic, text-book recursion. This routine has a very small
- * stack frame, so the recursion isn’t very expensive in this case. Document
- * lists are normally very short too.
- *
- * This routine disposes of every document list entry in a linked list of
- * document list entries starting from the entry docListEntry. If docListEntry
- * isn’t NIL and it isn’t a valid DocListEntryHnd, DisposeAllDocEntries probably
- * blows up in very bad ways.
- *******************************************************************************)
-
- PROCEDURE DisposeAllDocEntries (docListEntry: DocListEntryHnd);
-
- BEGIN
- IF docListEntry <> NIL THEN
- BEGIN
- IF docListEntry^^.next <> NIL THEN
- DisposeAllDocEntries (docListEntry^^.next);
- DisposHandle (Handle(docListEntry))
- END
- END;
-
-
- {$S ProcessUtils}
- (*******************************************************************************
- * Public: DisposeDocList
- *
- * Should be pretty obvious how this works.
- *******************************************************************************)
-
- PROCEDURE DisposeDocList (theList: DocListHnd);
-
- BEGIN
- IF theList <> NIL THEN
- BEGIN
- (* Dispose of all document list entries *)
- DisposeAllDocEntries (theList^^.docList);
-
- (* Dispose of the document list record *)
- DisposHandle (Handle(theList))
- END
- END;
-
-
- {$S ProcessUtils}
- (*******************************************************************************
- * Public: WereInFront
- *
- * The current application’s process serial number can always be represented by
- * setting the high long integer to 0 and setting the low long integer to the
- * constant kCurrentProcess. This process serial number is compared against the
- * process serial number of the front application. If they’re the same, then
- * this application is the front application.
- *******************************************************************************)
-
- FUNCTION WereInFront: Boolean;
-
- VAR
- thisProcess: ProcessSerialNumber; {Current process’s PSN}
- frontProcess: ProcessSerialNumber; {Front process’s PSN}
- inFront: Boolean; {TRUE if we’re in front}
- error: OSErr;
-
- PROCEDURE RecoverError (errorCode: OSErr);
-
- BEGIN
- WereInFront := TRUE;
- EXIT (WereInFront)
- END;
-
- BEGIN
- (* Make a PSN for this application *)
- thisProcess.highLongOfPSN := 0;
- thisProcess.lowLongOfPSN := kCurrentProcess;
-
- (* Get the PSN of the front process *)
- error := GetFrontProcess ((*<*)frontProcess);
- IF error <> noErr THEN
- RecoverError (error);
-
- (* See if this application is the front process *)
- error := SameProcess (thisProcess, frontProcess, (*<*)inFront);
- IF error <> noErr THEN
- RecoverError (error);
-
- WereInFront := inFront
- END;
-
-
- {$S ProcessUtils}
- (*******************************************************************************
- * Private: CreateDocListDesc - Create an AE descriptor for a list of documents
- *
- * This routine takes a document list in the "docList" parameter and converts it
- * to an 'appa' (typeAppParameters) AppleEvent descriptor containing a list of
- * documents to be opened by the Process Manager’s LaunchApplication routine.
- * This descriptor is returned.
- *
- * To do this, we have to first build an AppleEvent for an 'odoc'
- * (kAEOpenDocuments) or a 'pdoc' (kAEPrintDocuments) event that contains the
- * same list of documents that are contained in the "theDocList" parameter. Once
- * that’s done, this AppleEvent is coerced into an typeAppParameters descriptor.
- *
- * To create the kAEOpenDocuments or kAEPrintDocuments AppleEvent, a target
- * address descriptor is needed. Because we’re converting the AppleEvent into a
- * typeAppParameters descriptor rather than sending it somewhere, it doesn’t
- * matter what target address we use. I just used the process serial number
- * (PSN) of this application as a dummy value. Because this is an application
- * and not something like a driver, I can just use the "kCurrentProcess" constant
- * to represent this application’s PSN. A descriptor is made of this PSN, then
- * this PSN is used when creating the new kAEOpenDocuments AppleEvent. Once this
- * AppleEvent is created, the PSN descriptor is no longer needed and is disposed
- * of.
- *
- * kAEOpenDocuments AppleEvents needs a list of file aliases; each file alias
- * represents a document to open. To do this, a new descriptor list is created,
- * and an alias record is created. Then, each document in the "theDocList"
- * parameter is converted to an alias in the alias record, then the alias record
- * is manually converted into an 'alis' (typeAlias) descriptor. I did this
- * manually because an alias is already a handle, and it didn’t seem necessary to
- * go through the extra expense of the AECreateDesc routine. This typeAlias
- * descriptor is then added to the descriptor list we created earlier in this
- * paragraph. Once the entire document list is converted to the descriptor list,
- * the alias record is no longer needed and is disposed of.
- *
- * This descriptor list full of document aliases is then added to the
- * kAEOpenDocuments AppleEvent I created. Because the descriptor list is copied
- * into the AppleEvent, it is disposed of after the AEPutParamDesc call.
- *
- * Then, the most crucial call is made, AECoerceDesc. This routine coerces the
- * AppleEvent we just made into a typeAppParameters descriptor. The record
- * specified by the dataHandle of this descriptor is exactly in the same format
- * as the AppParameters record defined in the “Launching Other Applications”
- * section of the Process Manager chapter of Inside Macintosh VI.
- *
- * You can HLock the dataHandle, then set the "launchAppParameters" field of the
- * LaunchParamBlockRec to the dereferenced dataHandle. LaunchApplication can
- * then launch the specified application with the document list that was created.
- * If the launched application is high-level event aware (as specified in its
- * SIZE resource), the Process Manager converts LaunchAppParameters back to a
- * real high-level event which is processed by the application to (hopefully)
- * open the documents. Remember that LaunchAppParameters can be any high-level
- * event, but it’ll usually be used to pass an 'odoc' or 'pdoc' event, and that’s
- * what we’re using here. If the launched application isn’t high-level event
- * aware, and if LaunchAppParameters is an 'odoc' or 'pdoc' event, then the
- * Process Manager will convert the 'odoc' or 'pdoc' event into the old-style
- * application parameters so that an old-style application can still open
- * documents properly.
- *
- * This routine is important. Read it. Understand it. Then teach me how it
- * works.
- *******************************************************************************)
-
- FUNCTION CreateDocListDesc (theDocList: DocListHnd;
- VAR launchDesc: AEDesc): OSErr;
-
- CONST
- kPutAtEnd = 0; {For AEPutDesc; put new descriptor at end of list}
-
- VAR
- applMessage: AppleEvent; {odoc/pdoc event w/ spec’d doc list}
- docDescList: AEDescList; {Desc list of doc alias descs}
- selfPSN: ProcessSerialNumber; {Our own PSN; not really used here}
- selfAddress: AEDesc; {Desc for our own PSN; ditto}
- docDesc: AEDesc; {Desc for doc alias}
- docAlias: AliasHandle; {Alias for specified docs}
- currDocEntry: DocListEntryHnd; {Handle to current doc list entry}
- openPrintCmd: AEEventID; {odoc or pdoc event?}
- wasChanged: Boolean; {TRUE if UpdateAlias changed alias}
- error: OSErr;
-
- PROCEDURE RecoverError (errorCode: Integer);
-
- BEGIN
- IF selfAddress.dataHandle <> NIL THEN
- error := AEDisposeDesc ((*◊*)selfAddress);
- IF applMessage.dataHandle <> NIL THEN
- error := AEDisposeDesc ((*◊*)applMessage);
- IF docDescList.dataHandle <> NIL THEN
- error := AEDisposeDesc ((*◊*)docDescList);
- IF docAlias <> NIL THEN
- DisposHandle (Handle(docAlias));
- CreateDocListDesc := errorCode;
- EXIT (CreateDocListDesc)
- END;
-
- BEGIN
- selfAddress.dataHandle := NIL;
- applMessage.dataHandle := NIL;
- docDescList.dataHandle := NIL;
- docAlias := NIL;
-
- (* Make descriptor for my own PSN; just for AECreateAppleEvent’s yuks *)
- selfPSN.highLongOfPSN := 0;
- selfPSN.lowLongOfPSN := kCurrentProcess;
- error := AECreateDesc (typeProcessSerialNumber, @selfPSN,
- SIZEOF (ProcessSerialNumber), (*<*)selfAddress);
- IF error <> noErr THEN
- RecoverError (error);
-
- (* Create an AppleEvent for our list of document descriptors *)
- IF theDocList^^.openPrint = kOpenLaunch THEN
- openPrintCmd := kAEOpenDocuments
- ELSE IF theDocList^^.openPrint = kPrintLaunch THEN
- openPrintCmd := kAEPrintDocuments;
- error := AECreateAppleEvent (kCoreEventClass, openPrintCmd, selfAddress,
- kAutoGenerateReturnID, kAnyTransactionID, (*<*)applMessage);
- IF error <> noErr THEN
- RecoverError (error);
-
- (* PSN copied into the odoc or pdoc event, so don’t need it anymore *)
- error := AEDisposeDesc ((*◊*)selfAddress);
-
- (* Create list of descriptors for files; don’t use list factorization *)
- error := AECreateList (NIL, 0, FALSE, (*<*)docDescList);
- IF error <> noErr THEN
- RecoverError (error);
-
- (* Create an alias for the first document *)
- currDocEntry := theDocList^^.docList;
- HLock (Handle(currDocEntry));
- error := NewAlias (NIL, currDocEntry^^.docFile, (*<*)docAlias);
- HUnlock (Handle(currDocEntry));
- IF error <> noErr THEN
- RecoverError (error);
-
- (* Put each document in the document list into document descriptor list *)
- WHILE currDocEntry <> NIL DO
- BEGIN
- (* Convert alias into an alias descriptor manually *)
- docDesc.descriptorType := typeAlias;
- docDesc.dataHandle := Handle(docAlias);
-
- (* Put the alias descriptor into the document descriptor list *)
- error := AEPutDesc ((*◊*)docDescList, kPutAtEnd, docDesc);
- IF error <> noErr THEN
- RecoverError (error);
-
- (* Go to the next document in the document list *)
- currDocEntry := currDocEntry^^.next;
-
- (* Convert the next document’s FSSpec into the alias *)
- IF currDocEntry <> NIL THEN
- BEGIN
- HLock (Handle(currDocEntry));
- error := UpdateAlias (NIL, currDocEntry^^.docFile,
- (*<*)docAlias, (*<*)wasChanged);
- HUnlock (Handle(currDocEntry));
- IF error <> noErr THEN
- RecoverError (error)
- END
- END;
-
- (* All aliases are in docDescList, so don’t need the alias record *)
- DisposHandle (Handle(docAlias));
- docAlias := NIL;
-
- (* Put the descriptor list of documents into the odoc or pdoc event *)
- error := AEPutParamDesc ((*◊*)applMessage, keyDirectObject, docDescList);
- IF error <> noErr THEN
- RecoverError (error);
-
- (* The descriptor list is copied into the odoc event, so get rid of it *)
- error := AEDisposeDesc (docDescList);
-
- (* Convert the odoc event to a descriptor suitable for the launch PB *)
- error := AECoerceDesc (applMessage, typeAppParameters, (*<*)launchDesc);
- IF error <> noErr THEN
- RecoverError (error);
-
- (* We’re really interested in launchDesc, so don’t need odoc message *)
- error := AEDisposeDesc (applMessage);
-
- CreateDocListDesc := noErr
- END;
-
-
- {$S ProcessUtils}
- (*******************************************************************************
- * Private: SendOpenAppEvent - Send an 'oapp' event to an application
- *
- * When an application that is high-level event aware (as indicated by the SIZE
- * resource flag), it won’t open an untitled document at launch until it gets an
- * 'oapp' AppleEvent. This routine sends an 'oapp' event to the application
- * specified by the processNum parameter.
- *
- * First, a descriptor is created that contains the process serial number of the
- * target application. This descriptor is then added to the 'oapp' AppleEvent.
- * Finally, this AppleEvent is sent to the target application which should open
- * an untitled document in response.
- *
- * This routine isn’t called if the application is to open specific documents
- * when it’s launched.
- *
- * If an error occurs, the error code is returned.
- *******************************************************************************)
-
- FUNCTION SendOpenAppEvent (processNum: ProcessSerialNumber): OSErr;
-
- VAR
- theBaby: AEAddressDesc; {PSN desc. of process that’s been opened}
- openEvent: AppleEvent; {'oapp' AppleEvent}
- reply: AppleEvent; {Reply from receiving application; ignored}
- error: OSErr;
-
- PROCEDURE RecoverError (errorCode: Integer);
-
- BEGIN
- IF theBaby.dataHandle <> NIL THEN
- error := AEDisposeDesc ((*◊*)theBaby);
- IF openEvent.dataHandle <> NIL THEN
- error := AEDisposeDesc ((*◊*)openEvent);
- IF reply.dataHandle <> NIL THEN
- error := AEDisposeDesc ((*◊*)reply);
- SendOpenAppEvent := errorCode;
- EXIT (SendOpenAppEvent)
- END;
-
- BEGIN
- theBaby.dataHandle := NIL;
- openEvent.dataHandle := NIL;
- reply.dataHandle := NIL;
-
- (* Create the Process Serial Number event descriptor *)
- error := AECreateDesc (typeProcessSerialNumber, Ptr(@processNum),
- SIZEOF (ProcessSerialNumber), (*<*)theBaby);
- IF error <> noErr THEN
- RecoverError (error);
-
- (* Create 'oapp' event with the specified process serial number *)
- error := AECreateAppleEvent (kCoreEventClass, kAEOpenApplication,
- theBaby, kAutoGenerateReturnID, kAnyTransactionID, (*<*)openEvent);
- IF error <> noErr THEN
- RecoverError (error);
-
- (* Send the 'oapp' event *)
- error := AESend (openEvent, (*<*)reply, kAENoReply, kAENormalPriority,
- 0, NIL, NIL);
- IF error <> noErr THEN
- RecoverError (error);
-
- (* Dispose of the descriptor and event *)
- error := AEDisposeDesc ((*◊*)theBaby);
- error := AEDisposeDesc ((*◊*)openEvent);
- IF reply.dataHandle <> NIL THEN
- error := AEDisposeDesc ((*◊*)reply)
- END;
-
-
- {$S ProcessUtils}
- (*******************************************************************************
- * Private: LaunchProcApp - Launch an application
- *
- * This routine saves a bit of work when launching an application because it sets
- * up the launch parameter block and manages the construction of the application
- * list descriptor. The application to open is specified in processFile. If
- * there are any documents for the application to open when it’s launched, then
- * the document list is passed in docList. If there aren’t any documents for the
- * application to open, then docList is NIL. The options parameter specifies the
- * options to use when launching. This contains the values for the LaunchFlags
- * data type specified in the Process Manager chapter of Inside Macintosh VI.
- *
- * The process serial number of the specified process is returned in the
- * processNum parameter. The function result and the launchError parameter both
- * return error codes. One error is returned as a function result. These kinds
- * of errors are generated by any call that occurs during the execution of
- * LaunchProcess that is only used to manage the launching of the specified
- * application rather than launching the application itself. The launchError
- * parameter returns the error code of any error that occurs when the application
- * is actually launched.
- *******************************************************************************)
-
- FUNCTION LaunchProcApp (processFile: FSSpec;
- docList: DocListHnd;
- options: LaunchFlags;
- VAR processNum: ProcessSerialNumber;
- VAR launchError: OSErr): OSErr;
-
- VAR
- launchParms: LaunchParamBlockRec; {Parameters for launching a file}
- launchDesc: AEDesc; {Document file list descriptor}
- appParms: AppParametersPtr; {Pointer to the app parameters}
- error: OSErr;
-
- PROCEDURE RecoverError (errorCode: OSErr);
-
- BEGIN
- IF launchDesc.dataHandle <> NIL THEN
- BEGIN
- HUnlock (Handle(launchDesc.dataHandle));
- error := AEDisposeDesc (launchDesc)
- END;
- LaunchProcApp := errorCode;
- EXIT (LaunchProcApp)
- END;
-
- BEGIN
- launchError := noErr;
- launchDesc.dataHandle := NIL;
-
- (* Create the document list descriptor, if there’s a document list *)
- IF docList <> NIL THEN
- BEGIN
- error := CreateDocListDesc (docList, (*<*)launchDesc);
- IF error <> noErr THEN
- RecoverError (error);
- HLock (Handle(launchDesc.dataHandle));
-
- (* Descriptor dataHandle in format suitable for LaunchApplication *)
- appParms := AppParametersPtr(launchDesc.dataHandle^)
- END
- ELSE
- appParms := NIL;
-
- (* Set up the launch parameters *)
- WITH launchParms DO
- BEGIN
- (*WITH*)launchBlockID := extendedBlock;
- (*WITH*)launchEPBLength := extendedBlockLen;
- (*WITH*)launchFileFlags := 0;
- (*WITH*)launchControlFlags := options;
- (*WITH*)launchAppSpec := @processFile;
- (*WITH*)launchAppParameters := appParms
- END;
-
- (* Launch the process *)
- launchError := LaunchApplication (@launchParms);
-
- (* Get rid of the document descriptor list, if there was one *)
- IF docList <> NIL THEN
- BEGIN
- HUnlock (Handle(launchDesc.dataHandle));
- error := AEDisposeDesc (launchDesc)
- END
- ELSE
- (* No document descriptor list, so send oapp AppleEvent *)
- IF launchError = noErr THEN
- error := SendOpenAppEvent (launchParms.launchProcessSN);
-
- (* If the launch was successful, return the PSN of the process *)
- IF launchError = noErr THEN
- processNum := launchParms.launchProcessSN;
-
- LaunchProcApp := noErr
- END;
-
-
- {$S ProcessUtils}
- (*******************************************************************************
- * Private: GetFirstDAName - Get name of first
- *
- * GetFirstDAName gets the name of the first desk accessory in the file specified
- * by daFile. This name is returned in the daName parameter. GetFirstDAName
- * returns TRUE if a desk accessory was found in the file. If no desk accessory
- * could be found, then GetFirstDAName returns FALSE and the daName parameter is
- * unchanged.
- *
- * Desk accessories are stored in DRVR resources, but device drivers are also
- * stored in DRVR resources. GetFirstDAName will not return the names of device
- * drivers. How do you tell whether a DRVR resource is a desk accessory or a
- * device driver? Simply check on the first character of the DRVR resource’s
- * name. If it’s a null character, then you’ve got a desk accessory. If it’s
- * any other character, then you’ve got a device driver.
- *******************************************************************************)
-
- FUNCTION GetFirstDAName (daFile: FSSpec;
- VAR daName: Str255): Boolean;
-
- VAR
- currRF: Integer; {Ref num of current resource file}
- daRF: Integer; {Ref num of DA’s resource file}
- drvrRsrc: Handle; {Handle to a DRVR resource}
- drvrID: Integer; {ID number of drvrRsrc}
- drvrType: ResType; {Type of resource}
- drvrName: Str255; {Name of resource}
- numDRVRs: Integer; {Number of DRVR resources in the file}
- index: Integer; {Index into DRVR resources}
- daFound: Boolean; {TRUE if a DA was found in daFile}
-
- BEGIN
- daFound := FALSE;
-
- (* Save the current resource file ref num so we can restore it later *)
- currRF := CurResFile;
-
- (* Open the specified resource file *)
- daRF := FSpOpenResFile (daFile, fsRdPerm);
- IF daRF <> -1 THEN
- BEGIN
- (* Ready to check each DRVR; only checking, so set ResLoad false *)
- SetResLoad (FALSE);
- index := 1;
- numDRVRs := Count1Resources ('DRVR');
-
- (* Check each DRVR until all checked or a DA was found *)
- WHILE (index <= numDRVRs) AND (NOT daFound) DO
- BEGIN
- drvrRsrc := Get1IndResource ('DRVR', index);
-
- (* Get information about the resource *)
- IF drvrRsrc <> NIL THEN
- BEGIN
- GetResInfo (drvrRsrc, (*<*)drvrID, (*<*)drvrType,
- (*<*)drvrName);
-
- (* Find out whether it’s a DA or not *)
- IF (drvrName [0] > CHR (0)) & (drvrName [1] = CHR (0))
- THEN
- daFound := TRUE
- ELSE
- index := SUCC (index)
- END
- END;
-
- (* Restore the resource file and reset ResLoad *)
- SetResLoad (TRUE);
- CloseResFile (daRF)
- END;
-
- (* Get name of first DA in the file, or nil string if none found *)
- IF daFound THEN
- daName := drvrName
- ELSE
- daName [0] := CHR (0);
- GetFirstDAName := daFound;
- UseResFile (currRF)
- END;
-
-
- {$S ProcessUtils}
- (*******************************************************************************
- * Public: FindProcess
- *
- * The critical routine called by FindProcess is the GetProcessInfo routine. The
- * process information it returns is checked against "testFile", and against
- * "daName" if a desk accessory is being checked. If they’re equal, then
- * FindProcess returns TRUE and puts the process information in "testFileInfo".
- * If the entire Process Manager process list is searched without finding a
- * match, then FALSE is returned.
- *******************************************************************************)
-
- FUNCTION FindProcess (testFile: FSSpec;
- daName: StringPtr;
- VAR testFileInfo: ProcessInfoRec): Boolean;
-
- VAR
- procInfo: ProcessInfoRec; {Information on process being checked}
- procNum: ProcessSerialNumber; {Serial num of process being checked}
- procName: Str31; {Name of open process}
- procSpec: FSSpec; {File spec of open process’s file}
- procFound: Boolean; {TRUE if matching DA was found}
- error: OSErr;
-
- BEGIN
- (* Start checking from first process in Process Manager’s list *)
- procNum.highLongOfPSN := 0;
- procNum.lowLongOfPSN := kNoProcess;
-
- (* Loop through entire list of open processes or until match *)
- procFound := FALSE;
- WHILE (NOT procFound) & (GetNextProcess ((*◊*)procNum) = noErr) DO
- BEGIN
- (* Get information about an open process *)
- procInfo.processInfoLength := SIZEOF (ProcessInfoRec);
- procInfo.processName := @procName;
- procInfo.processAppSpec := @procSpec;
- error := GetProcessInformation (procNum, (*◊*)procInfo);
-
- (* Is it the same file as the one we’re testing? *)
- IF error <> noErr THEN
- IF EqualFSSpec (procInfo.processAppSpec^, testFile) THEN
- (* Yes; if it’s an application, we’ve found matching app *)
- IF BAND (procInfo.processMode, modeDeskAccessory) = 0 THEN
- procFound := TRUE
- ELSE
- (* Is it the same DA as the one we’re testing?
- IF EqualString (procInfo.processName^, daName^,
- NOT kCaseSens, kDiacSens) THEN
- (* Yes, we’ve found the matching DA *)
- procFound := TRUE
- END;
-
- IF procFound THEN
- testFileInfo := procInfo;
- FindProcess := procFound
- END;
-
-
- {$S ProcessUtils}
- (*******************************************************************************
- * Private: LaunchProcDA - Launch a desk accessory
- *
- * This routine launches the desk accessory that’s in the file specified by
- * process file and with the name specified by daName. If daName is NIL, then
- * the first desk accessory in the file, according to Get1IndResource, is
- * launched.
- *
- * As of 7.0b1, LaunchDeskAccessory doesn’t quite work as advertised in Inside
- * Macintosh VI if the desk accessory that it’s launching is already open.
- * Inside Macintosh VI says that the open desk accessory that’s being launched is
- * simply brought to the front. What I’ve found is that LaunchDeskAccessory
- * doesn’t do anything but return opWrErr. If the file that the desk accessory
- * is in is locked, then a new copy of the desk accessory is opened. I didn’t
- * quite like either of those actions, so I explicitly check to see whether the
- * desk accessory that I’m about to launch is already open. If it is, then I
- * call SetFrontProcess myself to bring it to the front.
- *
- * To check for this case, I first make sure that I have a name for the desk
- * accessory. LaunchDeskAccessory accepts NIL as a desk accessory name if the
- * caller wants to launch the first desk accessory that the Process Manager finds
- * in the specified file. My routine, LaunchProcess, also allows this. But I
- * don’t know what the Process Manager thinks is the first desk accessory in the
- * file. Since I’m comparing the characteristics of the desk accessory I’m about
- * to open against the list of open processes, and since I don’t know which desk
- * accessory is about to be launched if I leave the choice up to the Process
- * Manager, I just go and get the first desk accessory in the specified file
- * myself by calling my routine, GetFirstDAName. Now that I’m guaranteed to have
- * a name for the desired desk accessory, I don’t have to second-guess the
- * Process Manager’s choice for the “first” desk accessory in the specified file.
- *
- * You can’t tell LaunchDeskAccessory that you want to terminate after the desk
- * accessory is launched, so I terminate myself by calling ExitToShell if the
- * terminate parameter was set to TRUE. You also can’t tell LaunchDeskAccessory
- * that you want the desk accessory launched into the background. I still
- * haven’t thought of a clean way to do this, so for now, I don’t offer that as
- * an option. I can think of a few dirty ways.
- *******************************************************************************)
-
- FUNCTION LaunchProcDA (processFile: FSSpec;
- daName: StringPtr;
- options: LaunchFlags;
- VAR processNum: ProcessSerialNumber;
- VAR launchError: OSErr): OSErr;
-
- VAR
- procInfo: ProcessInfoRec; {Used to search open processes}
- procNum: ProcessSerialNumber; {Process serial num of open process}
- firstDAName: Str255; {File’s 1st DA name if none spec’d}
- daOpen: Boolean; {TRUE if spec’d DA is already open}
- error: OSErr;
-
- BEGIN
- error := noErr;
- launchError := noErr;
-
- (* If no DA name specified, get name of first DA in processFile *)
- IF daName = NIL THEN
- IF GetFirstDAName (processFile, (*<*)firstDAName) THEN
- IF firstDAName [0] > CHR (0) THEN
- daName := @firstDAName
- ELSE
- daName := NIL;
-
- (* If got name for new DA, see if DA process open w/ same name and file *)
- IF daName <> NIL THEN
- daOpen := FindProcess (processFile, daName, (*<*)procInfo)
- ELSE
- daOpen := FALSE;
-
- (* Launch the DA to the front, or set it to front if already launched *)
- IF daOpen THEN
- error := SetFrontProcess (procInfo.processNumber)
- ELSE
- launchError := LaunchDeskAccessory (@processFile, daName);
-
- (* If the terminate flag is set, glad to oblige *)
- IF BAND (options, launchContinue) = 0 THEN
- ExitToShell;
-
- (* Return the process serial number of the DA *)
- IF (error = noErr) AND (launchError = noErr) THEN
- BEGIN
- daOpen := FindProcess (processFile, daName, (*<*)procInfo);
- IF daOpen THEN
- processNum := procInfo.processNumber
- ELSE
- BEGIN
- procInfo.processNumber.highLongOfPSN := 0;
- procInfo.processNumber.lowLongOfPSN := kNoProcess;
- processNum := procInfo.processNumber
- END
- END;
-
- LaunchProcDA := error
- END;
-
-
- {$S ProcessUtils}
- (*******************************************************************************
- * Public: LaunchProcess
- *
- * The terminate and foreground parmeters are used to set up the flags for
- * launching in the launchOptions variable. The launch parameter block is set up
- * with the specified file and launch flags.
- *
- * If the launchContinue flags is clear, then the LaunchApplication function
- * doesn’t return even if it fails.
- *******************************************************************************)
-
- FUNCTION LaunchProcess (processFile: FSSpec;
- daName: StringPtr;
- docList: DocListHnd;
- options: LaunchFlags;
- VAR returnPSN: ProcessSerialNumber;
- VAR launchError: OSErr): OSErr;
-
- VAR
- fileInfo: FInfo; {File information for file to launch}
- newPSN: ProcessSerialNumber; {PSN of launched application}
- error: OSErr;
-
- PROCEDURE RecoverError (errorCode: OSErr);
-
- BEGIN
- LaunchProcess := errorCode;
- EXIT (LaunchProcess)
- END;
-
- BEGIN
- launchError := noErr;
-
- (* Find out whether file to launch is APPL or something else *)
- error := FSpGetFInfo (processFile, (*<*)fileInfo);
- IF error <> noErr THEN
- RecoverError (error);
-
- (* Launch the process *)
- IF fileInfo.fdType = 'APPL' THEN
- BEGIN
- (* File to be launched is an application; launch it *)
- error := LaunchProcApp (processFile, docList, options, (*<*)newPSN,
- (*<*)launchError);
- IF error <> noErr THEN
- RecoverError (error);
- END
- ELSE
- BEGIN
- (* File to be launch is a desk accessory; launch it *)
- error := LaunchProcDA (processFile, daName, options, (*<*)newPSN,
- (*<*)launchError);
- IF error <> noErr THEN
- RecoverError (error)
- END;
-
- (* Return the PSN of the new process *)
- IF launchError = noErr THEN
- returnPSN := newPSN;
-
- LaunchProcess := noErr
- END;
-
-
- {$S ProcessUtils}
- (*******************************************************************************
- * Public: CountProcesses
- *
- * It’s a pretty simple and straightforward algorithm.
- *******************************************************************************)
-
- FUNCTION CountProcesses: Integer;
-
- VAR
- procNum: ProcessSerialNumber; {Serial num of process being checked}
- procCount: Integer; {Number of processes found}
-
- BEGIN
- (* Start checking from first process in Process Manager’s list *)
- procNum.highLongOfPSN := 0;
- procNum.lowLongOfPSN := kNoProcess;
-
- (* Loop through entire list of open processes *)
- procCount := 0;
- WHILE GetNextProcess ((*◊*)procNum) = noErr DO
- procCount := SUCC (procCount);
-
- (* Return the number of processes found *)
- CountProcesses := procCount
- END;
-
-
- {$S ProcessUtils}
- (*******************************************************************************
- * Public: TerminateProcess
- *
- * Terminating a process is done by sending a 'quit' AppleEvent to the process
- * whose process serial number is given by "theProcessNum".
- *******************************************************************************)
-
- FUNCTION TerminateProcess (theProcessNum: ProcessSerialNumber): OSErr;
-
- VAR
- theDoomed: AEAddressDesc; {PSN descriptor of process to be terminated}
- quitEvent: AppleEvent; {'quit' AppleEvent}
- reply: AppleEvent; {Reply from receiving application; ignored}
- error: OSErr;
-
- PROCEDURE RecoverError (error: Integer);
-
- VAR
- result: OSErr;
-
- BEGIN
- IF theDoomed.dataHandle <> NIL THEN
- result := AEDisposeDesc ((*◊*)theDoomed);
- IF quitEvent.dataHandle <> NIL THEN
- result := AEDisposeDesc ((*◊*)quitEvent);
- TerminateProcess := error;
- EXIT (TerminateProcess)
- END;
-
- BEGIN
- theDoomed.dataHandle := NIL;
- quitEvent.dataHandle := NIL;
- reply.dataHandle := NIL;
-
- (* Create the Process Serial Number event descriptor *)
- error := AECreateDesc (typeProcessSerialNumber, Ptr(@theProcessNum),
- SIZEOF (theProcessNum), (*<*)theDoomed);
- IF error <> noErr THEN
- RecoverError (error);
-
- (* Create 'quit' event with the specified process serial number *)
- error := AECreateAppleEvent (kCoreEventClass, kAEQuitApplication,
- theDoomed, kAutoGenerateReturnID, kAnyTransactionID, (*<*)quitEvent);
- IF error <> noErr THEN
- RecoverError (error);
-
- (* Send the 'quit' event *)
- error := AESend (quitEvent, (*<*)reply, kAENoReply,
- kAENormalPriority, kNoTimeOut, NIL, NIL);
- IF error <> noErr THEN
- RecoverError (error);
-
- (* PSN in the AppleEvent, so can dispose of PSN descriptor *)
- error := AEDisposeDesc ((*◊*)theDoomed);
-
- (* Dispose of the 'quit' AppleEvent *)
- error := AEDisposeDesc ((*◊*)quitEvent)
- END;
-